#pragma once
#include "Sock.hpp"
#include <assert.h>
#include <poll.h>

#define FD_NONE -1 // 每个fd的初始化的值
#define NFDS 100 // 数组元素个数

class PollServer
{
public:
    PollServer(uint16_t port = 8080)
        : _port(port)
        , _nfds(NFDS)
    {
        // 创建套接字
        _listenSock = Sock::Socket();
        
        // bind绑定
        Sock::Bind(_listenSock, _port);

        // 设置监听状态
        Sock::Listen(_listenSock);

        // 开辟空间
        _fds = new pollfd[_nfds];
        for(int i = 0; i < _nfds; ++i)
        { // 初始化
            _fds[i].fd = FD_NONE;
            _fds[i].events = _fds[i].revents = 0;
        }

        // 第零个位置给成listenSock
        _fds[0].fd = _listenSock;
        _fds[0].events = POLLIN; // 关系listenSock的读
    }

    void showFds()
    {
        std::cout << "fds:: ";
        for(int i = 0; i < _nfds; ++i)
        {
            if(_fds[i].fd == FD_NONE) continue;
            
            std::cout << _fds[i].fd << ' ';
        }
        std::cout << std::endl;
    }

    void Start()
    {
        while(1)
        {
            showFds();

            // 1s间隔
            int res = poll(_fds, _nfds, -1);
            if(res > 0)
            { // 有文件描述符就绪
                std::cout << "some fds' ready" << std::endl;
                EventHandler();
            }
            else if(res == 0)
            { // 超时
                std::cout << "time out" << std::endl;
            }
            else
            { // poll出错
                printf("poll err, errno[%d], strerror::%s", errno, strerror(errno));
            }
        }
    }

    void EventHandler()
    {
        for(int i = 0; i < _nfds; ++i)
        {
            // 第i位不是有效文件描述符
            if(_fds[i].fd == FD_NONE) continue;
            
            // 读事件时候就绪
            if(_fds[i].revents & POLLIN)
            {
                if(i == 0)
                    Accepter();
                else
                    Reader(i);                
            }
        }
    }

    // 接收连接
    void Accepter()
    {
        // 获取连接
        std::string clientIP;
        uint16_t clientPort;
        int sock = Sock::Accept(_listenSock, clientIP, clientPort);

        // 找空位置放sock
        int pos = 1;
        for(; pos < _nfds; ++pos)
        {
            if(_fds[pos].fd == FD_NONE) break;
        }

        if(pos == _nfds)
        { // 没找到，不过这里也可以选择对_fds进行扩容，但是我懒得搞了，你要是有兴趣可以自己搞一下
            std::cout << "_nfds is full" << std::endl;
            close(sock);
        }
        else
        { // 找到了
            std::cout << "get a new link ::" << sock << std::endl;
            _fds[pos].fd = sock;
            _fds[pos].events = POLLIN;
        }
    }

    // 读取数据
    void Reader(int pos)
    {
        char buff[128];
        int res = read(_fds[pos].fd, buff, sizeof(buff) - 1);
        if(res > 0)
        { // 读取到数据
            buff[res] = 0;
            std::cout << "client #" << buff << std::endl;
        }
        else if(res == 0)
        { // 对端关闭连接
            std::cout << "client closed" << std::endl;
            // 记得后续工作
            close(_fds[pos].fd);
            _fds[pos].fd = FD_NONE;
            _fds[pos].events = _fds[pos].events = 0;
        }
        else
        { // 读取出错
            printf("read err, errno[%d], strerror::%s", errno, strerror(errno));
            // 记得后续工作
            close(_fds[pos].fd);
            _fds[pos].fd = FD_NONE;
            _fds[pos].events = _fds[pos].events = 0;
        }
    }

    ~PollServer()
    {
        if(_listenSock >= 0) close(_listenSock);

        if(_fds != nullptr) delete[] _fds;
    }


private:
    uint16_t _port;
    int _listenSock;
    pollfd *_fds;
    int _nfds;
};
